/*
 * @(#)RuleMemberFactory.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.rules.core;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mandarax.eca.Action;
import org.mandarax.kernel.ComplexTerm;
import org.mandarax.kernel.ConstantTerm;
import org.mandarax.kernel.Fact;
import org.mandarax.kernel.Predicate;
import org.mandarax.kernel.Prerequisite;
import org.mandarax.kernel.Rule;
import org.mandarax.kernel.Term;
import org.mandarax.kernel.VariableTerm;
import org.mandarax.lib.math.IntArithmetic;
import org.mandarax.lib.text.StringArithmetic;
import org.mandarax.util.LogicFactorySupport;

import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.UserInfoFactory;
import com.dcivision.framework.Utility;
import com.dcivision.rules.RuleOperationConstant;
import com.dcivision.rules.action.RuleActionSetAction;
import com.dcivision.rules.bean.RuleBaseObject;
import com.dcivision.rules.bean.RuleConclusion;
import com.dcivision.rules.bean.RuleCondition;

/**
 * <p>Class Name:  RuleMemberFactory</p> 
 * <p>Description: This class offer some function to get the rule member.</p>
 * 
 * @author        Tony Chen
 * @company       DCIVision Limited
 * @creation date 25/07/2005
 * @version       $Revision: 1.22 $
 */
public class RuleMemberFactory {

	protected Log log = LogFactory.getLog(this.getClass().getName());
	
	public RuleMemberFactory() {		
	}
		
	
	/**
	 * get the RuleBaseObject from the rule.
	 * @param rule  a rule
	 * @return RuleBaseObject
	 */
	public RuleBaseObject getRuleData(Rule rule){
		if (Utility.isEmpty(rule)) {
			return null;
		}
		RuleBaseObject ruleBaseObj = new RuleBaseObject();
		log.debug("rule is " + rule); 
		
		log.debug(rule.getKey());
		log.debug(rule.getBody());
		log.debug(rule.getContainer());
		log.debug(rule.getHead());
		log.debug(rule.getHead().getKey());
		log.debug(rule.getHead().getContainer());
		log.debug(rule.getProperties());
		
		//set the rule source
		ruleBaseObj.setRuleSource(rule);    
		
		//set the rule Property
		ruleBaseObj.setID( new Integer( rule.getProperty( RuleOperationConstant.RULE_ID ) ) );
		ruleBaseObj.setRuleID( rule.getProperty( RuleOperationConstant.RULE_ID  ) );
		ruleBaseObj.setRuleName( rule.getProperty(RuleOperationConstant.RULE_NAME) );
		ruleBaseObj.setRuleType( rule.getProperty(RuleOperationConstant.RULE_TYPE ) );
		ruleBaseObj.setRuleCategory( rule.getProperty(RuleOperationConstant.RULE_CATEGORY) );
		ruleBaseObj.setDescription( rule.getProperty(RuleOperationConstant.RULE_DESCRIPTION) );
		ruleBaseObj.setConditionRealtion( rule.getProperty(RuleOperationConstant.RULE_CONDITION_RELATION) );
		ruleBaseObj.setRuleSeqNo( rule.getProperty(RuleOperationConstant.RULE_SEQ_NO) );
		ruleBaseObj.setApplyOther( GlobalConstant.TRUE.equals(rule.getProperty(RuleOperationConstant.RULE_NOT_APPLY_OTHER)) );
		ruleBaseObj.setRuleEnable( rule.getProperty(RuleOperationConstant.RULE_STATUS_ENABLED) );
		ruleBaseObj.setDetailDescription( rule.getProperty(RuleOperationConstant.RULE_DETAIL_DEACRIPTION) );
    
		ruleBaseObj.setCreatorID( new Integer( rule.getProperty(RuleOperationConstant.RULE_CREATOR_ID) ) );
		ruleBaseObj.setCreateDate( TextUtility.parseDBDateTimeToTimeStamp( rule.getProperty(RuleOperationConstant.RULE_CREATE_DATE) ) );
		ruleBaseObj.setUpdaterID( new Integer( rule.getProperty(RuleOperationConstant.RULE_UPDATER_ID) ) );
		ruleBaseObj.setUpdateDate( TextUtility.parseDBDateTimeToTimeStamp( rule.getProperty(RuleOperationConstant.RULE_UPDATE_DATE) ) );
		ruleBaseObj.setUpdateCount( TextUtility.parseIntegerObj( rule.getProperty(RuleOperationConstant.RULE_UPDATE_COUNT) ) );
    
		//set the creator name & updater name
		ruleBaseObj.setCreatorName(UserInfoFactory.getUserFullName(ruleBaseObj.getCreatorID()));
		ruleBaseObj.setUpdaterName(UserInfoFactory.getUserFullName(ruleBaseObj.getUpdaterID()));
		
		//set the condition		
		ruleBaseObj.setCondition(this.getCondition(rule));
		
		//set the conclusion				
		ruleBaseObj.setConclusion(this.getConclusion(rule));
    
//    ruleBaseObj.setPrerequisiteList(ruleBaseObj.getConclusion());
//    ruleBaseObj.setActionFact(rule.getHead());
		
		return ruleBaseObj;
	}
	
	/**
	 * set the RuleBaseObject with the row number and the total number.
	 * @param ruleBaseObj  a RuleBaseObject
	 * @return RuleBaseObject
	 */
	public RuleBaseObject setRowNumRecordCount(RuleBaseObject ruleBaseObj, int rowNum, int totalNumOfRule){
	  //set the row number
		if ( rowNum > -1 ) {
		  ruleBaseObj.setRowNum(rowNum);
		}
		
		//set the total number of the record
		if ( totalNumOfRule > -1 ) {
			ruleBaseObj.setRecordCount(totalNumOfRule);
		}
		return ruleBaseObj;
	}
	
	/**
	 * get the rule condition from the rule, 
	 * get the condition list. A condition include a predicate and multi-term.
	 * @param rule a condition list 
	 * @return list
	 */
	public List getCondition(Rule rule){
		List conditionList = new ArrayList();
		
		//get the prerequisite list
		List prerequList = rule.getBody();		
		
		for(int i = 0; i < prerequList.size(); i++){
			RuleCondition condition = new RuleCondition();
			Fact fact = (Fact)prerequList.get(i);
			//get the predicte
			condition.setPredicateName(fact.getPredicate().getName());
			
			//get the term array			
			Term[] terms = fact.getTerms();
			if( !Utility.isEmpty(terms) ){
				String[] termArr = new String[terms.length];
				
				for (int j = 0; j < terms.length; j++) {
					Term term = terms[j];
					//Complex Term
					if( term instanceof ComplexTerm ){
						ComplexTerm clxTerm = (ComplexTerm)term;
						termArr[j] = clxTerm.getFunction().getName();
					
					//Constant Term	
					} else if ( term instanceof ConstantTerm ) {
						ConstantTerm conTerm = (ConstantTerm)term;
						termArr[j] = conTerm.getObject().toString();
					
					//Variable Term
					} else if ( term instanceof VariableTerm ) {
						VariableTerm varTerm = (VariableTerm)term;
						termArr[j] = varTerm.getName();
					}		
				}				
				condition.setTerm(termArr);
				
			}
			conditionList.add(condition);
			
		}		
		return conditionList;
	}
	
	/**
	 * get the conclusion from the rule
	 * @param rule a rule
	 * @return list
	 */
	public List getConclusion(Rule rule){		
		List conclusionList = new ArrayList();
		
		//get the fact
		Fact fact = rule.getHead();
		
		//get the term array			
		Term[] terms = fact.getTerms();
		log.debug("fact terms[] :" + fact.getTerms().length);
		
		if( !Utility.isEmpty(terms) ){
			String[] termArr = new String[terms.length];			
			for (int j = 0; j < terms.length; j++) {
				Term term = terms[j];
				if ( term instanceof ConstantTerm ) {
					ConstantTerm conTerm = (ConstantTerm)term;
					if (conTerm.getObject() instanceof com.dcivision.rules.action.RuleActionSetAction) {
						RuleActionSetAction actionSet = (RuleActionSetAction)(conTerm.getObject() );
						List actionList = actionSet.getActions();
						for (int h = 0; h < actionList.size(); h++) {
							Action action = (Action) actionList.get(h);
							RuleConclusion conclusion = new RuleConclusion();
							conclusion.setActionClassName(action.getClass().getName());
							conclusion.setParameter(TextUtility.splitString(action.getTarget().toString(), RuleOperationConstant.SPLIT_STRING ));
							
							conclusionList.add(conclusion);
							log.debug(" Class Name : " + conclusion.getActionClassName());
							log.debug(" Parameter (Target) : " + action.getTarget().toString());					
						}
						
					}					
				}		
			}				
 			
		}
		
		return conclusionList;
	}
	
	
	/**
	 * parse rule from RuleBaseObject
	 * @param ruleObj a RuleBaseObject 
	 * @return Rule
	 */
	public Rule parseRule(RuleBaseObject ruleObj ){		
		LogicFactorySupport lfs = new LogicFactorySupport();
	
		log.debug("Condition Realation is " + ruleObj.getConditionRealtion());
		log.debug("Prerequisite Lis is " + ruleObj.getPrerequisiteList());
		
		Rule rule = null;
		
		if ( Utility.isEmpty(ruleObj.getPrerequisiteList()) && 
         Utility.isEmpty(ruleObj.getActionFact()) && 
         !Utility.isEmpty(ruleObj.getRuleSource()) ) {
      rule = ruleObj.getRuleSource();
      
    } else {    	
    	if (Utility.isEmpty(ruleObj.getPrerequisiteList())) {
    		rule = lfs.rule( ruleObj.getActionFact() );
    	} else {
    		rule = lfs.rule(ruleObj.getPrerequisiteList(), ruleObj.getActionFact());
    	}
    }
		log.debug(ruleObj.getConditionRealtion());
		rule.setBodyOrConnected( !RuleOperationConstant.CONDITION_AND.equals(ruleObj.getConditionRealtion()) );
		log.debug("rule container: " + rule.getContainer());
		if(Utility.isEmpty(ruleObj.getDescription())){
      ruleObj.setDescription(ruleObj.getDetailDescription());
    }
        
		//set rule propertys 
		rule.setProperty( RuleOperationConstant.RULE_ID, ruleObj.getRuleID());
		rule.setProperty( RuleOperationConstant.RULE_NAME, ruleObj.getRuleName());
		rule.setProperty( RuleOperationConstant.RULE_TYPE, ruleObj.getRuleType());
		rule.setProperty( RuleOperationConstant.RULE_CATEGORY, ruleObj.getRuleCategory());
		rule.setProperty( RuleOperationConstant.RULE_DESCRIPTION, ruleObj.getDescription());
		rule.setProperty( RuleOperationConstant.RULE_CONDITION_RELATION, ruleObj.getConditionRealtion());
		rule.setProperty( RuleOperationConstant.RULE_SEQ_NO, TextUtility.formatNumberWithZeroPrefix(6, new Integer(ruleObj.getRuleSeqNo()) ) );
		rule.setProperty( RuleOperationConstant.RULE_NOT_APPLY_OTHER, ruleObj.isApplyOther() ? GlobalConstant.TRUE : GlobalConstant.FALSE );
		rule.setProperty( RuleOperationConstant.RULE_STATUS_ENABLED, ruleObj.getRuleEnable() );
		rule.setProperty( RuleOperationConstant.RULE_DETAIL_DEACRIPTION, ruleObj.getDetailDescription() );
		
		rule.setProperty( RuleOperationConstant.RULE_CREATOR_ID, ruleObj.getCreatorID().toString());
		rule.setProperty( RuleOperationConstant.RULE_CREATE_DATE, Utility.getCurrentTimestamp().toString() );
		rule.setProperty( RuleOperationConstant.RULE_UPDATER_ID, ruleObj.getUpdaterID().toString());
		rule.setProperty( RuleOperationConstant.RULE_UPDATE_DATE, Utility.getCurrentTimestamp().toString() );		
    rule.setProperty( RuleOperationConstant.RULE_UPDATE_COUNT, ruleObj.getUpdateCount().toString() );
		
		return rule;
	}
	
	/**
	 * parse prereauisite list
	 * @param ruleObj a Rule Base Object
	 * @return List
	 */
	public List parsePrerequisiteList (RuleBaseObject ruleObj ){
		List prereqList = new ArrayList();
		LogicFactorySupport lfs = new LogicFactorySupport();
		
		List conditionList = ruleObj.getCondition();
		
		for(int i = 0; i < conditionList.size(); i++){
			Prerequisite prereq = null;
			RuleCondition condition = (RuleCondition) conditionList.get(i);		
		}
		return null;
	}
	
	/**
	 * get a predicate
	 * @param predicate  a predicate string
	 * @return Predicate
	 */
	public Predicate getPredicate(String predicate){
		if(RuleOperationConstant.PREDICATE_TYPE_EQUAL.equals(predicate)){
			return StringArithmetic.EQUAL;      
		
		} else if(RuleOperationConstant.PREDICATE_TYPE_CONTAINES.equals(predicate)){
		  return StringArithmetic.CONTAINS;	
		
		} else if (RuleOperationConstant.PREDICATE_TYPE_GREATER_THAN_OR_EQUAL.equals(predicate)){
			return IntArithmetic.GREATER_THAN_OR_EQUAL;
		
    } else if (RuleOperationConstant.PREDICATE_TYPE_CONTAINES_ARRAY.equals(predicate)){
      return com.dcivision.rules.core.StringArithmetic.CONTAINS_ARRAY; 
      
    } else if(RuleOperationConstant.PREDICATE_TYPE_EQUAL_IGNORE_CASE.equals(predicate)){
      return StringArithmetic.EQUAL_IGNORE_CASE;
      
    } else if (RuleOperationConstant.PREDICATE_TYPE_CONTAINES_EQUALS.equals(predicate)) {
      return com.dcivision.rules.core.StringArithmetic.CONTAIN_EQUALS;  
    }
    
		return StringArithmetic.EQUAL;
	}
}	
